<script lang="ts" setup>
import { reactive, ref, onMounted, onActivated, shallowRef } from 'vue'
import SearchPlace from '@/components/map/SearchPlace.vue'
import LocusControlGroup from '@/components/map/LocusControlGroup.vue'
import { useMap } from '@/hooks/useMap'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import { useRoute } from 'vue-router'
import { getToken } from '@/utils/cache/cookies'
import { queryBikeShortTermTrack } from '@/api/bike'
import { queryBikeShortTermTrackResponseData, coordinatesType } from '@/api/bike/types/bike'
import { useActivated } from '@/hooks/useActivated'
import MarkerIcon from '@/assets/map/bikeLocus/marker.png'
import StartMarkerIcon from '@/assets/map/bikeLocus/startmarker.png'
import EndMarkerIcon from '@/assets/map/bikeLocus/endmarker.png'
import CircleImg from '@/assets/map/bikeLocus/circle.png'
import ActiveCircleImg from '@/assets/map/bikeLocus/activecircle.png'
import MeasureTools from '@/components/map/MeasureTools.vue'
defineOptions({
  name: 'TimeBikeLocus'
})
dayjs.extend(duration)
const route = useRoute()
/** 请求方法 */
const watchParams = reactive({
  orderId: '',
  bikeId: route.query.bikeId as string,
  storeId: route.query.storeId as string
})
const originData = ref<queryBikeShortTermTrackResponseData>()
const getData = async () => {
  try {
    reset()
    const res = await queryBikeShortTermTrack({
      ...watchParams,
      token: getToken() ?? ''
    })
    if (res.statusCode === '0') {
      if (res.data.bikeGpsList !== null) {
        originData.value = res.data
        coordinates.value = handleCoordinates(res.data.coordinates)
        await handleStartAndEnd()
        handleOriginData()
        handleCoverInit()
        initPoint()
      } else {
        ElMessage.error('暂无数据')
      }
    }
  } catch (error) {
    console.error(error)
  }
}
/** 地图初始化 */
const loading = ref<boolean>(false)
const isInit = ref<boolean>(false)
const mapContainer = ref<HTMLDivElement>()
const center = reactive({
  longtitude: 0,
  latitude: 0
})
const { map, auto, initAmap, placeSearch, geocoder, ruler } = useMap(mapContainer, [
  Number(center.longtitude),
  Number(center.latitude)
])
const init = async () => {
  isInit.value = await initAmap()
  handleInit()
}
const handleInit = () => {
  if (isInit.value && map.value) {
    getData()
  }
}

/** 处理开始骑行点与结束骑行点 */
interface startType {
  LngLat: AMap.LngLat | null
  unlockTime: string
  address: string
}
interface endType {
  LngLat: AMap.LngLat | null
  lockTime: string
  address: string
}
const start = reactive<startType>({ LngLat: null, unlockTime: '', address: '' })
const end = reactive<endType>({ LngLat: null, lockTime: '', address: '' })
const diffDate = ref<string>('')
const handleStartAndEnd = async () => {
  const data = originData.value?.bikeGpsList
  const firstGps = data![0]
  const lastGps = data![data!.length - 1]
  start.unlockTime = firstGps.recordTime
  end.lockTime = lastGps.recordTime
  start.LngLat = new AMap.LngLat(+firstGps.longtitude, +firstGps.latitude)
  end.LngLat = new AMap.LngLat(+lastGps.longtitude, +lastGps.latitude)
  diffDate.value = getDateDiff(firstGps.recordTime, lastGps.recordTime)
  try {
    const address = await getAddress([start.LngLat, end.LngLat])
    start.address = address[0].formattedAddress
    end.address = address[1].formattedAddress
  } catch (error) {
    console.error(error)
  }
}
const polyLinePath = ref<AMap.LngLat[]>([])
const handleOriginData = () => {
  const bikeGpsList = originData.value?.bikeGpsList
  polyLinePath.value = bikeGpsList!.map((item) => new AMap.LngLat(+item.longtitude, +item.latitude))
}
/**
 * @method handleCoverInit 处理数据生成地图覆盖物
 * @constant marker 骑行车辆
 * @constant polyLines - 每个开关锁数据的轨迹线段数组
 * @constant passedPolyline - 车辆轨迹播放时经过的线段
 * @constant startMarker 开锁点
 * @constant endMarker 关锁点
 * @constant stepMarkers stepMarker横跨点数组
 */
const marker = ref<AMap.Marker>()
const polyLine = ref<AMap.Polyline>()
const passedPolyline = ref<AMap.Polyline>()
const startMarker = ref<AMap.Marker>()
const endMarker = ref<AMap.Marker>()
const coordinates = ref<AMap.LngLat[]>([])
const distance = ref<number>(0)
const handleCoverInit = () => {
  marker.value = new AMap.Marker({
    map: map.value!,
    position: start.LngLat!,
    icon: MarkerIcon,
    offset: new AMap.Pixel(-29, -53),
    topWhenClick: true
  })
  if (coordinates.value.length > 0) {
    const polygon = new AMap.Polygon({
      path: coordinates.value,
      strokeColor: '#418DFF',
      strokeOpacity: 1,
      strokeWeight: 3,
      fillColor: '#418DFF',
      fillOpacity: 0.1,
      strokeStyle: 'dashed',
      bubble: true
    })
    map.value?.add(polygon)
  }
  polyLine.value = new AMap.Polyline({
    map: map.value!,
    path: polyLinePath.value,
    strokeColor: '#606266',
    strokeOpacity: 1,
    strokeWeight: 6,
    strokeStyle: 'solid',
    showDir: true,
    lineJoin: 'round'
  })
  distance.value = AMap.GeometryUtil.distanceOfLine(polyLinePath.value)
  //经过线段
  passedPolyline.value = new AMap.Polyline({
    map: map.value!,
    strokeColor: '#ff7880',
    strokeOpacity: 1,
    strokeWeight: 6,
    strokeStyle: 'solid',
    showDir: true,
    lineJoin: 'round'
  })
  //定义车辆回放轨迹事件 在执行moveTo，moveAlong动画时触发事件
  hanleContinueMarker()
  marker.value.on('moving', handleBikeMoving)
  startMarker.value = getStartMarkerCover(MarkerType.Start, -29, -53)
  endMarker.value = getEndMarkerCover(MarkerType.End, -28, -47)
  map.value?.setFitView([startMarker.value, endMarker.value])
}
/**
 * @description 轨迹回放事件回调函数
 * @param e 事件参数 包含 {index:number,process:number,type:string,passedPath:Proxy(t)[],passedPos:Proxy(t),pos:t}
 * @param process - 动画进程 当为1时代表 点到点的动画结束
 * @param index - 在轨迹数据数组中的index索引
 */
const handleBikeMoving = (e: any) => {
  if (e.progress === 1) {
    marker.value?.setLabel({
      content: `${originData.value?.bikeGpsList![e.index].recordTime}`,
      direction: 'top'
    })
  }
  passedPolyline.value?.setPath(e.passedPath)
}
/** 轨迹点初始化*/
const labelsLayer = shallowRef<AMap.LabelsLayer>() // 创建一个标注层实例
const textMarker = shallowRef<AMap.Text>()
const markerDuration = ref<number>(1000)
const initPoint = () => {
  const basicIcon = {
    type: 'image',
    // 图片 url
    image: CircleImg,
    // 图片尺寸
    size: [20, 20] as [number, number],
    anchor: 'center',
    clipOrigin: [0, 0] as [number, number],
    clipSize: [12, 12] as [number, number]
  }
  const basicActiveIcon = {
    type: 'image',
    // 图片 url
    image: ActiveCircleImg,
    // 图片尺寸
    size: [20, 20] as [number, number],
    anchor: 'center',
    clipOrigin: [0, 0] as [number, number],
    clipSize: [12, 12] as [number, number]
  }
  const MediumIcon = {
    type: 'image',
    // 图片 url
    image: CircleImg,
    // 图片尺寸
    size: [30, 30] as [number, number],
    anchor: 'center',
    clipOrigin: [0, 0] as [number, number],
    clipSize: [12, 12] as [number, number]
  }
  const mediumActiveIcon = {
    type: 'image',
    // 图片 url
    image: ActiveCircleImg,
    // 图片尺寸
    size: [30, 30] as [number, number],
    anchor: 'center',
    clipOrigin: [0, 0] as [number, number],
    clipSize: [12, 12] as [number, number]
  }
  // 创建一个标注层实例
  labelsLayer.value = new AMap.LabelsLayer({
    collision: false
  })
  textMarker.value = new AMap.Text({
    map: map.value!,
    anchor: 'top-center',
    topWhenClick: true,
    // style: {
    //   color: '#606266',
    //   backgroundColor: '#FFF',
    //   fontSize: '8px',
    //   padding: '10px 20px',
    //   'text-align': 'center'
    // }
    style: {
      padding: '5px 10px',
      marginTop: '1rem',
      borderRadius: '.25rem',
      backgroundColor: 'white',
      borderWidth: '0',
      boxShadow: '0 2px 6px 0 #606266',
      textAlign: 'center',
      fontSize: '10px',
      color: '#606266'
    }
  })
  const data = originData.value?.bikeGpsList
  polyLinePath.value.forEach((item, index) => {
    const labelMarker = new AMap.LabelMarker({
      position: item,
      extData: data?.[index],
      text: {
        content: (index + 1).toString(),
        direction: 'center',
        offset: index + 1 >= 100 ? [0, -3] : [0, -3],
        style: {
          fontSize: 8,
          fillColor: '#606266',
          padding: [0, 0, 0, 0]
        }
      },
      icon: index + 1 >= 100 ? MediumIcon : basicIcon
    })
    labelMarker.on('click', (e: any) => {
      labelsLayer.value?.getAllOverlays()?.forEach((item, index) => {
        item.setIcon(index >= 100 ? MediumIcon : basicIcon)
        const defaultText = {
          content: (index + 1).toString(),
          direction: 'center',
          offset: index + 1 >= 100 ? ([0, -3] as [number, number]) : ([0, -3] as [number, number]),
          style: {
            fontSize: 8,
            fillColor: '#606266',
            padding: [0, 0, 0, 0]
          }
        }
        const text = item.getText() ?? defaultText
        text.style!.fillColor = '#606266'
        item.setText(text)
      })
      textMarker.value?.setText(e.target.getExtData().recordTime)
      textMarker.value?.setPosition(e.target.getPosition())
      e.target.setIcon(e.target.getText() >= 100 ? mediumActiveIcon : basicActiveIcon)
      const text = e.target.getText()
      text.style.fillColor = '#FF7880'
      e.target.setText(text)
      textMarker.value?.show()
    })
    labelsLayer.value?.add(labelMarker)
  })
  map.value?.add(labelsLayer.value)
}
/** 重新初始化地图 即 清空 */
const reset = () => {
  map.value?.clearMap()
}
/** 速度变化 */
const handleSpeedChange = (speed: number) => {
  const basicSpeed = 1000
  markerDuration.value = basicSpeed / speed
  marker.value?.moveAlong(polyLinePath.value, {
    aniInterval: 0,
    autoRotation: false,
    duration: markerDuration.value
  })
}
/** 暂停 */
const handleStopMarker = () => {
  marker.value?.pauseMove()
}
/** 继续 */
const hanleContinueMarker = () => {
  if (
    (marker.value?.getPosition()?.getLat() === start.LngLat?.getLat() &&
      marker.value?.getPosition()?.getLng() === start.LngLat?.getLng()) ||
    (marker.value?.getPosition()?.getLat() === end.LngLat?.getLat() &&
      marker.value?.getPosition()?.getLng() === end.LngLat?.getLng())
  ) {
    marker.value?.moveAlong(polyLinePath.value, {
      aniInterval: 0,
      autoRotation: false,
      duration: markerDuration.value
    })
  } else {
    marker.value?.resumeMove()
  }
}

/** -------------------辅助函数-------------- */
/**
 * 用于生成content得点类型
 */
enum MarkerType {
  Start = 'start',
  End = 'end'
}
/**
 * 生成起点
 */
const getStartMarkerCover = (contentType: MarkerType, x: number, y: number) => {
  return new AMap.Marker({
    position: start.LngLat!,
    map: map.value!,
    offset: new AMap.Pixel(x, y),
    topWhenClick: true,
    icon: new AMap.Icon({
      image: StartMarkerIcon,
      size: new AMap.Size(59, 63),
      imageSize: new AMap.Size(59, 63)
    })
  })
}
/**
 * 生成终点
 */
const getEndMarkerCover = (contentType: MarkerType, x: number, y: number) => {
  return new AMap.Marker({
    position: end.LngLat!,
    map: map.value!,
    offset: new AMap.Pixel(x, y),
    anchor: 'middle-left',
    topWhenClick: true,
    icon: new AMap.Icon({
      image: EndMarkerIcon,
      size: new AMap.Size(59, 63),
      imageSize: new AMap.Size(59, 63)
    })
  })
}
/** 获取地址 */
const getAddress = (data: AMap.LngLat[] | AMap.LngLat): any => {
  return new Promise((resolve, reject) => {
    geocoder.value.getAddress(data, (status: string, result: any) => {
      if (status === 'complete') {
        if (Array.isArray(data)) {
          resolve(result.regeocodes)
        } else {
          resolve(result.regeocode)
        }
      } else {
        reject(new Error(`获取地址失败`))
      }
    })
  })
}
/** 计算骑行时间差 */
const getDateDiff = (startDateString: string, endDateString: string) => {
  // 创建起始日期和结束日期对象
  const startDate = dayjs(startDateString, 'YYYY-MM-DD HH:mm:ss')
  const endDate = dayjs(endDateString, 'YYYY-MM-DD HH:mm:ss')

  // 计算日期差异
  const diff = endDate.diff(startDate)
  console.log(diff)

  // 提取差异的时间单位
  const duration = dayjs.duration(diff)
  const years = duration.years()
  const months = duration.months()
  const days = duration.days()
  const hours = duration.hours()
  const minutes = duration.minutes()
  const seconds = duration.seconds()
  let formattedDiff = ''
  if (years > 0) formattedDiff = formattedDiff.concat(years + '年')
  if (months > 0) formattedDiff = formattedDiff.concat(months + '月')
  if (days > 0) formattedDiff = formattedDiff.concat(days + '天')
  if (hours > 0) formattedDiff = formattedDiff.concat(hours + '时')
  if (minutes > 0) formattedDiff = formattedDiff.concat(minutes + '分')
  if (seconds > 0) formattedDiff = formattedDiff = formattedDiff.concat(seconds + '秒')
  return formattedDiff
}
/** 转换数据用于初始化运营区域 */
const handleCoordinates = (data: coordinatesType[]) => {
  return data.map(
    (location: coordinatesType) => new AMap.LngLat(location.longtitude, location.latitude)
  )
}
onMounted(() => {
  init()
})
/** 处理是否缓存 */
onActivated(() => {
  watchParams.bikeId = route.query.bikeId as string
  watchParams.storeId = route.query.storeId as string
})
useActivated(
  watchParams,
  { watchParams },
  [
    { key: 'bikeId', path: 'watchParams.bikeId' },
    { key: 'storeId', path: 'watchParams.storeId' }
  ],
  getData,
  []
)
</script>

<template>
  <div class="xy-map-container">
    <div ref="mapContainer" id="map-container" v-loading="loading">
      <search-place :auto="auto" :map="map!" :place-search="placeSearch" />
      <locus-control-group
        @stop="handleStopMarker"
        @continue="hanleContinueMarker"
        @speed-change="handleSpeedChange"
      />
      <measure-tools :ruler="ruler" class="measure-tools-menu"></measure-tools>
      <div class="location-info">
        <div class="location-info__item">
          <img :src="StartMarkerIcon" alt="" w-15 h-15 mr-5 />
          <div border border-solid class="border-[#e4e7ed]" p-5 max-w-220 text-10>
            <span leading-snug>{{ start.address }}</span>
          </div>
        </div>
        <div class="location-info__item">
          <img :src="EndMarkerIcon" alt="" w-15 h-15 mr-5 />
          <div border border-solid class="border-[#e4e7ed]" p-5 max-w-220 text-10>
            <span leading-snug>{{ end.address }}</span>
          </div>
        </div>
        <div class="location-info__footer" text-8>
          <span mr-30>本次骑行用时:{{ diffDate }}</span>
          <span>本次骑行距离:{{ distance.toFixed(2) }}米</span>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
:deep(.address) {
  font-size: 14px;
  font-family: PingFang SC;
  line-height: 20px;
  color: var(--xy-medium-text-color);
}
:deep(.time) {
  font-size: 12px;
  font-family: PingFang SC;
  line-height: 17px;
  color: var(--xy-grey-text-color);
}
:deep(.amap-marker-label) {
  background-color: #fff;
  white-space: nowrap;
  cursor: default;
  padding: 3px;
  font-size: 12px;
  line-height: 14px;
  color: #333333;
  box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.25);
  border-radius: 4px 4px 4px 4px;
  border: none;
}
.location-info {
  position: absolute;
  z-index: 999;
  top: 80px;
  left: 20px;
  padding: 10px;
  border-radius: 4px 4px 4px 4px;
  background: #ffffff;
  display: flex;
  flex-direction: column;
  &__item {
    display: flex;
    align-items: center;
    margin-bottom: 15px;
  }
  &__footer {
    display: flex;
    align-items: center;
    justify-content: space-around;
  }
}
.measure-tools-menu {
  position: absolute;
  top: 20px;
  right: 70px;
  z-index: 200;
  background-color: #fff;
  padding: 10px 10px;
  box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.1);
  border-radius: 5px 5px 5px 5px;
}
</style>
